#!/usr/bin/python
'''
This file accept and executes nbdxadm cmds
'''


__author__ = "Max Gurtovoy"
__version__ = '2.0'

import optparse
import sys
import os
import ConfigParser

'''
      CONFIGDIR is just general rpg host and device info 
      NBDX_CONFIGFS is the detailed info
'''
CONFIGDIR = '/etc/rpg'
CONFIGFILE = os.path.join(CONFIGDIR, 'rpg.ini')
CONFIGFS = '/sys/kernel/config'
NBDX_CONFIGFS = os.path.join(CONFIGFS, 'rpg')


# Jun: non-important
def is_configfs_mounted():
    found = False
    for l in open('/proc/mounts').readlines():
        dev, path, fs, opts, freq, passno = l.split()
        if fs == 'configfs' and path == '/sys/kernel/config':
            found = True
            break

    return found


def get_host_devices(host, parser):
    devices = []
    for section in parser.sections():
        if parser.has_option(section, 'host'):
            if parser.get(section, 'host') == host:
                devices.append(section)
    return devices


def createDevice(parser, opts):
    if opts.device_id is None:
        print "Missing host id"
        return 1
    nbdxdevice = 'rpg%d' % opts.device_id
    if opts.host_id is None:
        print "Missing host id"
        return 1
    nbdxhost = 'rpghost%d' % opts.host_id

    if not parser.has_section(nbdxhost):
        print 'host id %d is not configured' % opts.host_id
        return 1

    if parser.has_section(nbdxdevice):
        print 'device id %d is already configured' % opts.device_id
        return 1

    host_path = os.path.join(NBDX_CONFIGFS, nbdxhost)
    device_path = os.path.join(host_path, nbdxdevice)
    os.makedirs(device_path)
    try:
        with open(os.path.join(device_path, 'device'), 'w') as device_file:
            device_file.write(nbdxdevice)
    except IOError, e:
        print 'failed to create device: %s' % e
        os.rmdir(device_path)
        return 1

    parser.add_section(nbdxdevice)
    parser.set(nbdxdevice, 'host', nbdxhost)

    return 0


def deleteDevice(parser, opts):
    if opts.device_id is None:
        print "Missing device id"
        return 1

    nbdxdevice = 'rpg%d' % opts.device_id
    if not parser.has_section(nbdxdevice):
        print 'device id %d is not configured' % opts.device_id
        return 1
    else:
        nbdxhost = parser.get(nbdxdevice, 'host')
        host_path = os.path.join(NBDX_CONFIGFS, nbdxhost)
        device_path = os.path.join(host_path, nbdxdevice)
        os.rmdir(device_path)
        parser.remove_section(nbdxdevice)

    return 0


def createHost(parser, opts):
    if opts.host_id is None:
        print "Missing host id"
        return 1
    nbdxhost = 'rpghost%d' % opts.host_id
    if opts.portal is None:
        print 'Missing portal'
        return 1

    pf = open(opts.portal, 'r')
    p_count = 0
    p_str = ""
    for p_line in pf.readlines():
        if (p_line == '\n' or p_line is None):
            continue
        p_str += p_line.strip()
        p_str += ","
        p_count += 1
    pf.close()

    if parser.has_section(nbdxhost):
        print 'host id %d is already configured' % opts.host_id
        return 1

    for section in parser.sections():
        if parser.has_option(section, 'portal'):
            if opts.portal == parser.get(section, 'portal'):
                print 'Portal %s already exists' % opts.portal
                return 1

    host_path = os.path.join(NBDX_CONFIGFS, nbdxhost)
    os.makedirs(host_path)
    try:
        with open(os.path.join(host_path, 'portal'), 'w') as portal_file:
            portal_file.write(p_str)
    except IOError, e:
        print 'failed to create host: %s' % e
        os.rmdir(host_path)
        return 1

    parser.add_section(nbdxhost)
    parser.set(nbdxhost, 'portal', opts.portal)

    return 0


def deleteHost(parser, opts):
    rc = 0
    if opts.host_id is None:
        print "Missing host id"
        return 1

    nbdxhost = 'rpghost%d' % opts.host_id
    if not parser.has_section(nbdxhost):
        print 'host id %d is not configured' % opts.host_id
        return 1

    devices = get_host_devices(nbdxhost, parser)
    for device in devices:
        opts.device_id = int(device.strip('rpg'))
        c_rc = deleteDevice(parser, opts)
        if c_rc:
            print 'failed to delete %s' % device
            rc = c_rc or rc
    if not rc:
        host_path = os.path.join(NBDX_CONFIGFS, nbdxhost)
        os.rmdir(host_path)
        parser.remove_section(nbdxhost)
    else:
        print 'failed to delete host %d' % opts.host_id

    return rc


def showHost(parser, opts):
    if opts.host_id is None:
        print "Missing host id"
        return 1

    nbdxhost = 'rpghost%d' % opts.host_id
    if not parser.has_section(nbdxhost):
        print 'host id %d is not configured' % opts.host_id
        return 1
    print 'HOST: %s, PORTAL: %s' % (nbdxhost, parser.get(nbdxhost, 'portal'))
    return 0


def showHostDevices(parser, opts):
    if opts.host_id is None:
        print "Missing host id"
        return 1

    nbdxhost = 'rpghost%d' % opts.host_id
    if not parser.has_section(nbdxhost):
        print 'host id %d is not configured' % opts.host_id
        return 1
    devices = []
    for section in parser.sections():
        if parser.has_option(section, 'host'):
            if nbdxhost == parser.get(section, 'host'):
                devices.append(section)
    print 'HOST: %s, PORTAL: %s, DEVICES: %s' % (nbdxhost,
                                                 parser.get(
                                                     nbdxhost, 'portal'),
                                                 ', '.join(devices))
    return 0


def showAllHosts(parser, opts):
    for section in parser.sections():
        if parser.has_option(section, 'portal'):
            opts.host_id = int(section.strip('rpghost'))
            showHost(parser, opts)
    return 0


def showDevice(parser, opts):
    if opts.device_id is None:
        print "Missing device id"
        return 1

    nbdxdevice = 'rpg%d' % opts.device_id
    if not parser.has_section(nbdxdevice):
        print 'device id %d is not configured' % opts.device_id
        return 1
    # print 'DEVICE: %s, FILE: %s, HOST: %s, PORTAL: %s' % (nbdxdevice,
    #                                                       parser.get(
    #                                                           nbdxdevice, 'file'),
    #                                                       parser.get(
    #                                                           nbdxdevice, 'host'),
    # parser.get(parser.get(nbdxdevice, 'host'), 'portal'))
    print 'DEVICE: %s, HOST: %s, PORTAL: %s' % (nbdxdevice,
                                                parser.get(
                                                    nbdxdevice, 'host'),
                                                parser.get(parser.get(nbdxdevice, 'host'), 'portal'))
    return 0


def showAllDevices(parser, opts):
    for section in parser.sections():
        # if parser.has_option(section, 'file'):
        opts.device_id = int(section.strip('rpg'))
        showDevice(parser, opts)
    return 0


RUN_OPERATION = {'create_host': createHost,
                 'delete_host': deleteHost,
                 'show_host': showHost,
                 'show_host_devices': showHostDevices,
                 'show_all_hosts': showAllHosts,
                 'create_device': createDevice,
                 'delete_device': deleteDevice,
                 'show_device': showDevice,
                 'show_all_devices': showAllDevices,
                 }


def main():

    supported_operations = ["create_host",
                            "delete_host",
                            "show_host",
                            "show_host_devices",
                            "show_all_hosts",
                            "create_device",
                            "delete_device",
                            "show_device",
                            "show_all_devices"]

    create_host_usage = "\nnbdxadm -o create_host -i <host_id> -p <portal.file>\n"
    delete_host_usage = "nbdxadm -o delete_host -i <host_id>\n"
    show_host_usage = "nbdxadm -o show_host -i <host_id>\n"
    show_host_devices_usage = "nbdxadm -o show_host_devices -i <host_id>\n"
    show_all_hosts_usage = "nbdxadm -o show_all_hosts\n"
    create_device_usage = "nbdxadm -o create_device -i <host_id> -d <device_id>\n"
    delete_device_usage = "nbdxadm -o delete_device -d <device_id>\n"
    show_device_usage = "nbdxadm -o show_device -d <device_id>\n"
    show_all_devices_usage = "nbdxadm -o show_all_devices"
    usage = (create_host_usage + delete_host_usage + show_host_usage + show_host_devices_usage +
             show_all_hosts_usage + create_device_usage + delete_device_usage +
             show_device_usage + show_all_devices_usage)
    parser = optparse.OptionParser(usage=usage)
    parser.add_option('-o', '--op',
                      choices=supported_operations,
                      help="[%s]" % '|'.join(supported_operations),
                      dest="operation")
    parser.add_option('-p', '--portal',
                      type=str,
                      help="portal to create",
                      dest="portal")
    parser.add_option('-i', '--hid',
                      type=int,
                      help="host id",
                      dest="host_id")
    parser.add_option('-d', '--dev_id',
                      type=int,
                      help="device id",
                      dest="device_id")
    # parser.add_option('-f', '--file_path',
    #                   type=str,
    #                   help="file path",
    #                   dest="file_path")

    (opts, args) = parser.parse_args()

    if args:
        print 'error: invalid input,  check -h or --help'
        sys.exit(1)

    if not os.path.isdir(CONFIGFS):
        print "can't continue operation, check if configfs module is loaded"
        sys.exit(1)

    if not is_configfs_mounted():
        print "can't continue operation, please mount configfs i.e.:"
        print "\tmount -t configfs none /sys/kernel/config"
        sys.exit(1)

    if not opts.operation:
        print "Missing operation."
        sys.exit(1)

    if not os.path.isdir(NBDX_CONFIGFS):
        print "can't continue operation, check if rpg module is loaded"
        sys.exit(1)

    conf_parser = ConfigParser.ConfigParser()
    if not os.path.isdir(CONFIGDIR):
        os.makedirs(CONFIGDIR)
    conf_parser.read(CONFIGFILE)
    if conf_parser.sections() and not os.listdir(NBDX_CONFIGFS):
        conf_parser = ConfigParser.ConfigParser()
        with open(CONFIGFILE, 'w') as nbdx_conf_file:
            conf_parser.write(nbdx_conf_file)

    rc = RUN_OPERATION[opts.operation](conf_parser, opts)
    if rc:
        print "Invalid %s operation" % opts.operation
        sys.exit(1)

    with open(CONFIGFILE, 'w') as nbdx_conf_file:
        conf_parser.write(nbdx_conf_file)

    sys.exit(0)


if __name__ == "__main__":
    main()
